Frontend.ctrl.console = function() {
	var store = {
		speed: 10,
		loading: 150,
		locked: false,
		redirect: 1000,
		history: [],
		index: 0

	// display the welcome message
	}, _welcome = function() {
		var w = $('div.php_to_js', '#console');
			x = $.parseJSON(w.html());

		_text('Sunny Web Platform [Version 0.3d]' + '\n' +
			'(c) ' + x.year + ' ' + x.guild + '(tm). All rights reserved.' + '\n\n', 0, _end);

	// default end function to show cursor
	}, _end = function() {
		store.target.html(store.target.html().slice(0, -1));
		store.target.append('>');
		store.input.show().focus();
		store.locked = false;
		store.mask3.hide();

	// this is what happens when you press enter in the input field
	}, _cmd = function(e) {
		var x = store.input.val();
		if(!x.length > 0)
			return false;

		if(store.history[store.history.length - 1] != x)
			store.history.push(x);

		store.index = store.history.length;

		store.locked = true;
		store.mask3.show();
		store.input.val('').hide();
		store.target.append(' ' + x + '\n\n');

		_go(x);

	// this is what happens when you press arrow key up or down in the input field
	}, _history = function(dir) {
		// up
		if(dir) {
			if(store.index <= 0)
				return false;

			store.index--;

		// down
		} else {
			if(store.index == store.history.length)
				return false;

			store.index++;
		}

		// set value
		store.input.val(store.history[store.index]);

	// add some dots for loading / redirecting
	}, _loading = function(ignore) {
		if(!ignore)
			store.target.html(store.target.html().slice(0, -1));

		store.target.append('.');
		store.timeout = window.setTimeout(function () {
			_loading(true);
		}, store.loading);

	// output text on screen, simple
	}, _text = function(message, index, f) {
		window.clearTimeout(store.timeout);

		store.target.scrollTop(store.target[0].scrollHeight);
		if (index < message.length) {
			store.target.html(store.target.html().slice(0, -1));
			store.target.append(message[index++]);
			store.target.append('_');

			store.timeout = window.setTimeout(function () {
				_text(message, index, f);
			}, store.speed);

		// callback on end
		} else {
			if(f) f();
		}

	// display a table (supports just 2 headers)
	}, _tabular = function(header, data) {
		var o = '',
			len = {},
			limit = 35,
			__repeat = function(string, num) {
				if(num > limit) num = limit;
				return new Array(parseInt(num) + 1).join(string);
			}, __fill = function(string, num) {
				if(num > limit) num = limit;
				if(string.length < num)
					return string + __repeat(' ', num - string.length);
				else return string;
			}, __split1 = function(string, num, fill) {
				if(string.substr(limit).length > limit)
					return string.substr(0, limit) + ' | ' + __repeat(' ', num) + ' |\n| ' + __split1(string.substr(limit), num, fill);

				return string.substr(0, limit) + ' | ' + __repeat(' ', num) + ' |\n| ' + __fill(string.substr(limit), fill);
			}, __split2 = function(string, num, fill) {
				if(string.substr(limit).length > limit)
					return string.substr(0, limit) + ' |\n| ' + __repeat(' ', num) + ' | ' + __split2(string.substr(limit), num, fill);

				return string.substr(0, limit) + ' |\n| ' + __repeat(' ', num) + ' | ' + __fill(string.substr(limit), fill);
			};

		// calculate length from header
		$.each(header, function(k, v) {
			len[v] = v.length;
		});

		// calculate length from data
		$.each(data, function(a, b) {
			if(a.length > len[header[0]])
				len[header[0]] = a.length;

			if(b.length > len[header[1]])
				len[header[1]] = b.length;
		});

		// build header
		$.each(len, function(k, v) { o += '+-'+ __repeat('-', v) +'-'; }); o += '+\n';
		$.each(len, function(k, v) { o += '| '+ __fill(k, v) +' '; }); o += '|\n';
		$.each(len, function(k, v) { o += '+-'+ __repeat('-', v) +'-'; }); o += '+\n';

		// build data
		$.each(data, function(a, b) {
			var v = len[header[0]],
				w = len[header[1]];

			if(a.length > limit) {
				o += '| '+ __split1(a, w, v) +' ';
			} else {
				o += '| '+ __fill(a, v) +' ';
			}

			if(b.length > limit) {
				o += '| '+ __split2(b, v, w) +' ';
				o += '|\n';
			} else {
				o += '| '+ __fill(b, w) +' ';
				o += '|\n';
			}
		});

		// build footer
		$.each(len, function(k, v) { o += '+-'+ __repeat('-', v) +'-'; }); o += '+\n';

		return o;

	// execute a command
	}, _go = function(cmd) {
		var input = cmd.split(' ');
		switch (input[0]) {
			// command clear will clear the text
			case 'clear':
				store.target.html('');
				_end();
			break;

			// command help will show available commands
			case 'help':
				_text('Available commands are: `categories`, `ranks`, `rebuild`, `settings`, `set`,\n`get`, `backup`, `clear` and `help`.\n\n', 0, _end);
			break;

			// command categories will redirect you to categories management
			case 'categories':
				_text('Redirecting to Category Management', 0, _loading);
				window.setTimeout(function() {
					Frontend.go('categories');
				}, store.redirect);
			break;

			// command ranks will redirect you to ranks management
			case 'ranks':
				_text('Redirecting to Rank Management', 0, _loading);
				window.setTimeout(function() {
					Frontend.go('ranks');
				}, store.redirect);
			break;

			// command rebuild will rebuild the search index
			case 'rebuild':
				_text('Rebuilding search index', 0, _loading);
				Frontend.ajax({type: 'get', url: 'forum/rebuild', success: function(){
					_text('\nSearch index successfuly rebuilt.\n\n', 0, _end);
				}, error: function() {
					_text('\nError occured while trying to rebuild index.\n\n', 0, _end);
				}});
			break;

			// command settings will display all the settings variables and values associated with them
			case 'settings':
				_text('Displaying all variables...', 0, function() {
					Frontend.ajax({type: 'get', url: 'console/settings', success: function(data){
						var txt = '\n\n',
							old = store.speed;

						txt += _tabular(['key', 'value'], data.settings);

						store.speed = 0;
						_text(txt, 0, function() {
							store.speed = old;
							_text('\nUse `set` to asign new values or `get` to just load individual variables.\n\n', 0, _end);
						});
					}});
				});
			break;

			// command set will attempt to set a variable with the desired value
			case 'set':
				Frontend.ajax({type: 'post', data: {cmd: input}, url: 'console/set', success: function(data){
					_text('Assigned `' + data.value + '` to `' + input[1] + '`.\n\n', 0, function() {
						// on guild change ask to refresh the whole website
						if(input[1] == 'guild') {
							Frontend.noty({
								type: 'warning',
								text: input[1].charAt(0).toUpperCase() + input[1].slice(1) + ' was updated.<br />Refresh for changes?',
								buttons: [{text: 'Yes', onClick: function($noty) {
									$noty.close();
									window.location.href = window.location.href;
								}}, {text: 'No', onClick: function($noty) {
									$noty.close();
									_end();
								}}]
							});

						// else just refresh metro
						} else {
							// broadcast metro refresh
							Frontend.socket.metro();
							_end();
						}
					});
				}, error: function(data) {
					if(typeof input[1] == 'undefined')
						input[1] = '';

					var err = data.value ? 'Value is invalid. Example of syntax `set ' + input[1] + ' abc`.\n\n' :
						'Variable `' + input[1] + '` not found. Type `settings` to see the available variables.\n\n';

					_text(err, 0, _end);
				}});
			break;

			// command get will attempt to get the desired variable
			case 'get':
				Frontend.ajax({type: 'post', data: {cmd: input}, url: 'console/get', success: function(data){
					_text(data.value + '\n\n', 0, _end);
				}, error: function() {
					if(typeof input[1] == 'undefined')
						input[1] = '';

					_text('Variable `' + input[1] + '` not found. Type `settings` to see the available variables.\n\n', 0, _end);
				}});
			break;

			// command backup will create a backup of the database and serve the download
			case 'backup':
				Frontend.ajax({type: 'post', data: {cmd: input}, url: 'console/backup', success: function(data){
					// show all backups
					if(data.backups) {
						_text('Displaying all backups...', 0, function() {
							var txt = '\n\n',
								old = store.speed;

							txt += _tabular(['name', 'date'], data.backups);

							store.speed = 0;
							_text(txt, 0, function() {
								store.speed = old;
								_text('\nManage backups by using these commands: `save`, `restore`, `delete`.\n\n', 0, _end);
							});
						});

					// regular message
					} else _text(data.msg + '\n\n', 0, _end);
				}, error: function(data) {
					_text(data.msg.replace('{br}', '\n') + '\n\n', 0, _end);
				}});
			break;

			// easter egg, thx adi
			case 'lol':
				_text('~~~~~~lol~~~~~lol~~~lol~~~~~~~~. 3 people are now drowning, was it worth it?\n\n', 0, _end);
			break;

			// command was unrecognized.
			default:
				_text('Command `' + input[0] + '` not found. Please type `help` to see the available commands.\n\n', 0, _end);
			break;
		}

	// binder
	}, _bind = function() {
		// prevent mousewheel while text is active
		$('div.console > pre').on('mousewheel', function(e) {
			if(store.locked)
				e.preventDefault();
		});

		// on console scroll show or hide input
		$('div.console > pre').on('scroll', $.throttle(50, function() {
		    var self = $(this);

			// scrolled to bottom (note the 2pixels for border)
		    if(self[0].scrollHeight - self.scrollTop() == self.outerHeight() - 2) {
		    	if(!store.locked)
		        	store.input.show().focus();
		    } else store.input.hide();
		}));

		// on keys up
        store.input.on('keyup', function(e) {
        	// up
			if(e.keyCode == 38)
				_history(true);

        	// down
			if(e.keyCode == 40)
				_history(false);

        	// enter
            if(e.keyCode == 13)
				_cmd();
        });

		// on anykey down (besides ctrl shift and alt) focus console
		$(window).on('keydown', function(e) {
			if(e.shiftKey || e.altKey || e.ctrlKey)
				return true;

			store.input.focus();
		});

	// constructor
	}, __construct = function() {
		// set some things
		store.target = $('div.console > pre', '#console');
		store.input = $('div.console > input', '#console');
		store.mask3 = $('div.console > div.mask3', '#console');

		_bind();
		_welcome();
	};

	// public, yay
	return {
		init: __construct
	};
}();